**發文會切斷 ,請參考前一篇 URL: (https://ithelp.ithome.com.tw/articles/10398868) **
位置 /src/main/resources/templates/fragment
layout.html (new 系統排版版面)<!DOCTYPE html>
<html lang="UTF-8" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
<meta name="_csrf" th:content="${_csrf.token}"/>
<!-- default header name is X-CSRF-TOKEN -->
<meta name="_csrf_header" th:content="${_csrf.headerName}"/>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title layout:title-pattern="$CONTENT_TITLE - $LAYOUT_TITLE ">WEB APP</title>
<!-- Font Awesome -->
<link rel="stylesheet" th:href="@{/webjars/AdminLTE/3.2.0/plugins/fontawesome-free/css/all.min.css}">
<!-- overlayScrollbars -->
<link rel="stylesheet" th:href="@{/webjars/AdminLTE/3.2.0/plugins/overlayScrollbars/css/OverlayScrollbars.min.css}">
<!-- Theme style -->
<link rel="stylesheet" th:href="@{/webjars/AdminLTE/3.2.0/dist/css/adminlte.min.css}">
</head>
<body>
<!-- Site wrapper -->
<div class="wrapper">
<!-- Top Menu tree if isLayoutTop is true-->
<section th:if="${isLayoutTop}" th:insert="~{fragment/topMenu.html}"></section>
<!-- Side Menu tree if isLayoutTop is true -->
<section th:unless="${isLayoutTop}" th:insert="~{fragment/sideMenu.html}"></section>
<!-- Content Wrapper -->
<div class="d-flex flex-column">
<div class="container-wrapper">
<!-- Begin Page Content -->
<div class="container-fluid">
<!-- Content Section -->
<section layout:fragment="content">
<p>This is filled by the content template.
</section>
</div> <!-- End of Begin Page Content -->
</div> <!-- end Main Content -->
<!-- Main Footer -->
<footer class="main-footer">
<!-- To the right -->
<div class="float-right d-none d-sm-inline">
Anything you want
</div> <!-- Default to the right -->
<strong>Copyright © 2014-2021 <span> WebApp System</span>.</strong> All rights reserved.
</footer>
<!-- end Main Footer -->
<!-- PageEditModal modal -->
<div class="modal fade " id="PageEditModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-xl" role="document">
<div class="modal-content">
<div class="modal-body">
...
</div> <!-- end modal-body-->
</div> <!-- end model-content-->
</div> <!-- end modal-dialog-->
</div> <!-- end modal-->
</div> <!-- end Content Wrapper -->
</div> <!-- end Site wrapper -->
<!-- Custom scripts for all pages-->
<!-- jQuery -->
<script th:nonce="${nonce}" th:src="@{/webjars/AdminLTE/3.2.0/plugins/jquery/jquery.min.js}"></script>
<!-- Bootstrap 4 -->
<script th:nonce="${nonce}" th:src="@{/webjars/AdminLTE/3.2.0/plugins/bootstrap/js/bootstrap.bundle.min.js}"></script>
<!-- overlayScrollbars -->
<script th:nonce="${nonce}" th:src="@{/webjars/AdminLTE/3.2.0/plugins/overlayScrollbars/js/jquery.overlayScrollbars.min.js}"></script>
<!-- AdminLTE App -->
<script th:nonce="${nonce}" th:src="@{/webjars/AdminLTE/3.2.0/dist/js/adminlte.min.js}"></script>
<!-- dompurify -->
<!-- <script th:nonce="${nonce}" th:src="@{/webjars/dompurify/3.1.5/dist/purify.min.js}"></script> -->
<!--Layout.js -->
<script th:nonce="${nonce}" th:src="@{/js/baseLayout.js}"></script>
<!-- Optional Section -->
<th:block layout:fragment="optional.js" />
</body>
</html>
sideMenu.html (new 系統選單)<!DOCTYPE html> <!-- SideMenu -->
<html lang="UTF-8" xmlns:th="http://www.thymeleaf.org">
<body class="hold-transition sidebar-mini layout-fixed">
<!-- Main Sidebar Container --> <!-- 取得MeniItemNodel 物件內容 -->
<aside class="main-sidebar sidebar-dark-primary elevation-4" th:object="${MenuItemModelVar}">
<!-- Brand Logo -->
<a th:href="@{/chgMenuLayout}" class="brand-link">
<span class="brand-text font-weight-light" th:text="*{menuBarText}">AdminLTE 3</span>
</a>
<div class="sidebar">
<!-- Sidebar Header with Expand/Collapse Buttons -->
<div class="sidebar-header p-2">
<button id="expandAll" class="btn btn-sm btn-outline-light mr-1" title="全部展开"><i class="fas fa-expand">全部展開</i></button>
<button id="collapseAll" class="btn btn-sm btn-outline-light" title="全部折叠"><i class="fas fa-compress"></i>全部折叠</button>
</div>
<!-- Sidebar Menu -->
<nav class="mt-2 text-sm">
<ul class="nav nav-pills nav-sidebar flex-column" data-widget="treeview" role="menu" data-accordion="false">
<!-- 取得naviItem內容(迴圈) -->
<li class="nav-item menu-open" th:each="naviIs,naviStat:*{naviItems}">
<!-- 若不是menu類別,指定 Item URL -->
<a th:href="${naviIs.isMenu} ? '#' : (@{/doMenu(Url=${naviIs.menuUrl},Desc=${naviIs.menuDesc},Func=${naviIs.menuFunc})}) "
class="nav-link">
<!-- 若menu類別,顯示"+",否則顯示Play圓-->
<i th:class="${naviIs.isMenu} ? 'nav-icon fas fa-plus-square' : 'nav-icon far fa-play-circle'"></i>
<!-- 顯示Item文字-->
<p th:text="${naviIs.menuDesc}">Level 1</p>
<!-- 若menu類別,顯示"<"-->
<i th:if="${naviIs.isMenu}" class="right fas fa-angle-left"></i>
</a>
<!-- 若menu類別,指定Class為treeView-->
<ul th:if="${naviIs.isMenu}" class="nav nav-treeview">
<!-- 取得cloiapse內容(迴圈) -->
<li class="nav-item menu-open" th:each="colsIs,colsStat:${naviIs.collapseItems}">
<!-- 若不是menu類別,指定 Item URL -->
<a th:href="${colsIs.isMenu} ? '#' : (@{/doMenu(Url=${colsIs.menuUrl},Desc=${colsIs.menuDesc},Func=${colsIs.menuFunc})})"
class="nav-link">
<!-- 若menu類別,顯示實心圓,否則顯示Play圓-->
<i> </i><i th:class="${colsIs.isMenu} ? 'far fa-circle nav-icon' : 'far fa-play-circle nav-icon'"></i>
<!-- 顯示Item文字-->
<p th:text="${colsIs.menuDesc}">Level 2</p>
<!-- 若menu類別,顯示"<"-->
<i th:if="${colsIs.isMenu}" class="right fas fa-angle-left"></i>
</a>
<!-- 若menu類別,指定Class為treeView (可以再展開)-->
<ul th:if="${colsIs.isMenu}" class="nav nav-treeview">
<!-- 取得Sub cloiapse內容(迴圈) -->
<li th:each="subColsIs,subColsStat:${colsIs.collapseItems}" class="nav-item">
<!-- 應該是程序,直接指定URL-->
<a th:href="@{/doMenu(Url=${subColsIs.menuUrl},Desc=${subColsIs.menuDesc},Func=${subColsIs.menuFunc})}"
class="nav-link">
<!-- 應該是程序,直接顯示Play圓-->
<i> </i><i class="far fa-play-circle nav-icon"></i>
<!-- 顯示程序文字-->
<p th:text="${subColsIs.menuDesc}">Level 3</p>
</a>
</li> <!--End colsIs.collapseItems內容(subColsIs迴圈) -->
</ul> <!--第三層 menu類別 -->
</li><!--End naviIs.collapseItems(colsIs迴圈) -->
</ul> <!--第二層 menu類別 -->
</li> <!-- end naviItems(naviIs迴圈) -->
</ul> <!--第一層 menu類別 -->
</nav>
<!-- /.sidebar-menu -->
</div>
<!-- /.sidebar -->
</aside>
<div class="wrapper">
<!-- Navbar -->
<nav class="main-header navbar navbar-expand navbar-white navbar-light">
<!-- Left navbar links -->
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" data-widget="pushmenu" href="#" role="button"><i class="fas fa-bars"></i></a>
</li>
<li class="nav-item d-none d-sm-inline-block">
<div class="text-center">
<h2 id="content_title">Homexxxx</h2>
</div>
</li>
</ul>
<!-- Right navbar links -->
<ul class="navbar-nav ml-auto">
<li class="nav-item">
<!-- //https://www.w3schools.com/bootstrap4/tryit.asp?filename=trybs_tooltip_pos&stacked=h -->
<form id="logoutForm" class="nav-link form-inline mt-2 mt-md-0 col-6" th:action="@{/logoutSubmit}"
method="post">
<button class="fas fa-sign-out-alt ml-2 btn-primary btn-sm" type="submit"
sec:authentication="name"></button>
</form>
</li>
</ul>
</nav>
</div>
<!-- JavaScript for Expand/Collapse All -->
<script th:nonce="${nonce}" th:src="@{/webjars/AdminLTE/3.2.0/plugins/jquery/jquery.min.js}"></script>
<script th:nonce="${nonce}">
$(document).ready(function() {
$('#expandAll').click(function() {
$('li.nav-item').each(function() {
if ($(this).find('.nav-treeview').length > 0) {
$(this).addClass('menu-open');
$(this).find('.nav-treeview').show();
}
});
});
$('#collapseAll').click(function() {
$('li.nav-item').each(function() {
if ($(this).find('.nav-treeview').length > 0) {
$(this).removeClass('menu-open');
$(this).find('.nav-treeview').hide();
}
});
});
});
</script>
</body>
</html>
topMenu.html (new 系統選單)<!DOCTYPE html> <!-- TopMenu -->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<body class="hold-transition layout-top-nav">
<!-- TopMenubar (th:object="${MenuItemModelVar}" 後端傳入的menuItems物件)-->
<nav class="main-header navbar navbar-expand-sm navbar-dark" th:object="${MenuItemModelVar}">
<!-- "container" 版型Menu會置中, ontent-fluid版型Menu會靠左 -->
<div class="container-fluid"> <!-- "container" 版型Menu會置中, ontent-fluid版型Menu會靠左 -->
<a th:href="@{/chgMenuLayout}" class="navbar-brand"> <!-- 標題(brand) -->
<!--th:value="*{menuBarText}" 後端傳入的menuItems物件標題) -->
<span class="brand-text font-weight-light" th:text="*{menuBarText}">AdminLTE 3</span>
</a>
<!-- <button> 當顯示螢幕變小時調整為選項的按鈕(俗稱漢堡) -->
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbars"
aria-controls="navbars" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse order-3 text-sm" id="navbars">
<!-- th:each 迴圈處理第一層menuItems資料 -->
<div th:each="naviIs,naviStat:*{naviItems}">
<!-- 宣告第一層 Menu Nav -->
<ul class="navbar-nav">
<!-- th:unless 第一層menuItems資料不是 Menu類-->
<li th:unless="${naviIs.isMenu}" class="nav-item mt-3">
<!--是程序,直接指定URL 顯示Play圓-->
<a th:href="@{/doMenu(Url=${naviIs.menuUrl},Desc=${naviIs.menuDesc},Func=${naviIs.menuFunc})}" class="nav-link far fa-play-circle"
th:text="${naviIs.menuDesc}">level 1</a>
</li>
<!-- th:if 第一層menuItems資料是 Menu類(第一個下拉選單)-->
<li th:if="${naviIs.isMenu}" class="nav-item dropdown mt-2">
<!-- 顯示 Menu Item 說明-->
<a th:id="${'navi'+naviStat.index}" href="#" data-toggle="dropdown" aria-haspopup="true"
aria-expanded="false" class="nav-link dropdown-toggle" th:text="${naviIs.menuDesc}">Dropdown
</a>
<!-- 宣告第二層 Menu Nav -->
<ul class="dropdown-menu border-0 shadow bg-secondary" aria-labelledby="${'navi'+naviStat.index}">
<!-- 處理所有 第二層 collapseItems-->
<dev th:each="colsIs,colsStat:${naviIs.collapseItems}">
<!-- th:unless 第二層menuItems的資料不是 Menu類-->
<li th:unless="${colsIs.isMenu}">
<!--是程序,直接指定URL 顯示Play圓-->
<a tabindex="-1"
th:href="@{/doMenu(Url=${colsIs.menuUrl},Desc=${colsIs.menuDesc},Func=${colsIs.menuFunc})}"
class="dropdown-item far fa-play-circle" th:text="${colsIs.menuDesc}">level 2 menuUrl</a>
</li>
<!-- th:if 第二層menuItems資料是 Menu類(第二個下拉選單)-->
<!-- dropdown-hover 表示自動展開,看喜好-->
<li th:if="${colsIs.isMenu}" class="dropdown-submenu dropdown-hover">
<!-- 顯示 Menu Item 說明-->
<a th:id="${'colsIs'+colsStat.index}" href="#" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false" class="nav-link dropdown-toggle"
th:text="${colsIs.menuDesc}">Dropdown
</a>
<!-- 宣告第三層 Menu Nav -->
<ul class="dropdown-menu border-0 shadow bg-secondary"
aria-labelledby="${'colsIs'+colsStat.index}">
<!-- 處理所有 第三層 collapseItems-->
<dev th:each="subColsIs,subColsIsStat:${colsIs.collapseItems}">
<!-- 這裡應該只有 URL 顯示Play圓 ,有Menu類不處裡 -->
<li th:unless="${subColsIs.isMenu}">
<a tabindex="-1"
th:href="@{/doMenu(Url=${subColsIs.menuUrl},Desc=${subColsIs.menuDesc},Func=${subColsIs.menuFunc})}"
class="dropdown-item far fa-play-circle" th:text="${subColsIs.menuDesc}">level 3 menuUrl</a>
</li>
</dev> <!-- 第三層迴圈資料 End -->
</ul> <!-- end 宣告第三層 Menu Nav -->
</li> <!--第二個下拉選單 -->
</dev> <!-- 第二層Menu 迴圈資料 End -->
</ul><!-- end 宣告第二層 Menu Nav -->
</li>
</ul><!-- 第一層迴圈資料 End -->
</div>
<!-- Right navbar links 準備放一些靠右的資料 (例如登出logout按鈕建)-->
<ul class="order-1 order-md-3 navbar-nav navbar-no-expand ml-auto">
<form id="logoutForm" class="form-inline mt-2 mt-md-0" th:action="@{/logoutSubmit}" method="post">
<button class="fas fa-sign-out-alt ml-2 btn-primary btn-sm" type="submit" sec:authentication="name"></button>
</form>
</ul> <!--靠右的資料 End -->
</div> <!-- collapse End -->
</div> <!-- container-fluid -->
</nav>
<div class="text-center">
<h2 id="content_title">Homexxxx</h2>
</div>
</body>
</html>
位置 /src/main/resources/templates/home
1.homePage.html (revise 登入頁面)
<!DOCTYPE html>
<html lang="UTF-8" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/Layout">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>WebAppSystem | Log in</title>
<!-- Google Font: Source Sans Pro -->
<link rel="stylesheet" th:href="@{/webjars/AdminLTE/3.2.0/plugins/fontawesome-free/css/all.min.css}">
<!-- Theme style -->
<link rel="stylesheet" th:href="@{/webjars/AdminLTE/3.2.0/dist/css/adminlte.min.css}">
</head>
<body class="hold-transition login-page">
<div class="login-box">
<!-- /.login-logo -->
<div class="card card-outline card-primary">
<div class="card-header text-center">
<span class="h1"><b>Web App</b></span>
</div>
<div class="card-body">
<div>
</div>
<div th:if="${param.retry}">
<div class="alert alert-danger">Invalid username and password</div>
</div>
<div th:if="${param.logout}">
<div class="alert alert-danger">Logout Success.</div>
</div>
<div th:if="${param.expired}">
<div class="alert alert-danger">Session Expired.</div>
</div>
<form th:action="@{/loginSubmit}" method="post" AUTOCOMPLETE="off">
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
<div class="input-group mb-3">
<input id="useid" type="text" class="form-control" name="username" placeholder="UserName">
<div class="input-group-append">
<div class="input-group-text">
<span class="fas fa-user"></span>
</div>
</div>
</div>
<div class="input-group mb-3">
<input id="password" type="password" class="form-control" name="ePasscode" placeholder="Password"
autocomplete="false">
<div class="input-group-append">
<div class="input-group-text">
<span class="fas fa-lock"></span>
</div>
</div>
</div>
<div id="divCapsLock">Caps Lock is on.</div>
<button id="login" type="submit" class="btn btn-primary btn-block">Sign In</button>
<div class="social-auth-links text-center mt-2 mb-3">
<div th:each="url : ${urls}">
<a th:if="${url.key == 'GitHub'}" th:href="${url.value}" class="btn btn-block btn-primary">
<i class="fab fa-github mr-2"></i> Sign in using GitHub
</a>
<a th:if="${url.key == 'Google'}" th:href="${url.value}" class="btn btn-block btn-danger">
<i class="fab fa-google-plus mr-2"></i> Sign in using Google+
</a>
</div>
</div>
</form>
</div>
<!-- /.card-body -->
</div>
<!-- /.card -->
</div>
<!-- /.login-box -->
<!-- jQuery -->
<script th:nonce="${nonce}" th:src="@{/webjars/AdminLTE/3.2.0/plugins/jquery/jquery.min.js}"></script>
<!-- Bootstrap 4 -->
<script th:nonce="${nonce}" th:src="@{/webjars/AdminLTE/3.2.0/plugins/bootstrap/js/bootstrap.bundle.min.js}"></script>
<!-- AdminLTE App -->
<script th:nonce="${nonce}" th:src="@{/webjars/AdminLTE/3.2.0/dist/js/adminlte.min.js}"></script>
<script th:nonce="${nonce}" th:src="@{/js/capLock.js}"></script>
<!-- <script th:nonce="${nonce}" type="text/javascript">
$(document).ready(function() {
$('#divCapsLock').css('display', 'none');
document.body.addEventListener('keyup',(event) => {
capLock(event);
})
});
function capLock(e){
if (e.getModifierState("CapsLock")) {
$('#divCapsLock').css('display', 'block');
} else {
$('#divCapsLock').css('display', 'none');
}
}
</script> -->
</body>
</html>
2.landingPage.html (revise 登入成功頁面)
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/Layout"
layout:decorate="~{fragment/layout}">
<head>
<link th:href="@{/css/landingImg.css}" rel="stylesheet" />
</head>
<body>
<!-- 指定 id=intro, 使用head內的style Background image -->
<div id="intro" class="content-wrapper" layout:fragment="content">
<!-- 指定在置中(h-100) ,若 (h-50) 則以上半部(50%高度)置中-->
<div class="d-flex align-items-center h-100">
f <!-- 沒有 container 則 form 不會左右置中-->
<div class="container">
<div class="mx-auto text-center text-white">
<div class="row justify-content-center ">
<form class="bg-white rounded-2 shadow-5-strong p-5 ">
<h2>Welcome Section</h2>
<h4>歡迎 大駕光臨 </h4>
</form>
</div>
</div>
</div> <!-- row -->
</div> <!-- container -->
</div> <!--d-flex -->
</div> <!-- intro content -->
</body>
</html>
位置 /src/main/resources
menuItemsData.json Json 格式的選單資料{
"menuBarText": "Web App System",
"naviItems": [
{
"menuSeq": 30,
"isMenu": true,
"menuDesc": "系統查詢功能",
"menuUrl": "",
"menuFunc": "",
"menuRoles": "all",
"collapseItems": [
{
"menuSeq": 30,
"isMenu": false,
"menuDesc": "系統排程執行紀錄查詢",
"menuUrl": "/system/SysScheduleLogPage",
"menuFunc": "Inquiry",
"menuRoles": "all",
"collapseItems": []
},
{
"menuSeq": 30,
"isMenu": false,
"menuDesc": "系統存取紀錄查詢",
"menuUrl": "/system/SysAccessLogPage",
"menuFunc": "Inquiry",
"menuRoles": "all",
"collapseItems": []
},
{
"menuSeq": 20,
"isMenu": false,
"menuDesc": "系統Journal紀錄查詢",
"menuUrl": "/system/SysJournalLogPage",
"menuFunc": "Inquiry",
"menuRoles": "all",
"collapseItems": []
}
]
},
{
"menuSeq": 20,
"isMenu": true,
"menuDesc": "系統維護功能",
"menuUrl": "naviItemUrl_20",
"menuFunc": "",
"menuRoles": "all",
"collapseItems": [
{
"menuSeq": 10,
"isMenu": true,
"menuDesc": "系統使用者維護",
"menuUrl": "",
"menuFunc": "",
"menuRoles": "all",
"collapseItems": [
{
"menuSeq": 10,
"isMenu": false,
"menuDesc": "系統使用者查詢",
"menuUrl": "/system/SysUserProfilePage",
"menuFunc": "Inquiry",
"menuRoles": "all",
"collapseItems": []
},
{
"menuSeq": 20,
"isMenu": false,
"menuDesc": "系統使用者維護",
"menuUrl": "/system/SysUserProfilePage",
"menuFunc": "Edit",
"menuRoles": "all",
"collapseItems": []
},
{
"menuSeq": 20,
"isMenu": false,
"menuDesc": "系統使用者確認",
"menuUrl": "/system/SysUserProfilePage",
"menuFunc": "Confirm",
"menuRoles": "all",
"collapseItems": []
}
]
},
{
"menuSeq": 30,
"isMenu": true,
"menuDesc": "系統排程維護",
"menuUrl": "",
"menuFunc": "",
"menuRoles": "all",
"collapseItems": [
{
"menuSeq": 10,
"isMenu": false,
"menuDesc": "系統排程設定查詢",
"menuUrl": "/system/SysScheduleCtlPage",
"menuFunc": "Inquiry",
"menuRoles": "all",
"collapseItems": []
},
{
"menuSeq": 20,
"isMenu": false,
"menuDesc": "系統排程維護",
"menuUrl": "/system/SysScheduleCtlPage",
"menuFunc": "Edit",
"menuRoles": "all",
"collapseItems": []
},
{
"menuSeq": 20,
"isMenu": false,
"menuDesc": "系統排程確認",
"menuUrl": "/system/SysScheduleCtlPage",
"menuFunc": "Confirm",
"menuRoles": "all",
"collapseItems": []
}
]
},
{
"menuSeq": 30,
"isMenu": true,
"menuDesc": "系統參數維護功能",
"menuUrl": "",
"menuFunc": "",
"menuRoles": "all",
"collapseItems": [
{
"menuSeq": 20,
"isMenu": false,
"menuDesc": "系統參數查詢",
"menuUrl": "/system/SysParmDataPage",
"menuFunc": "Inquiry",
"menuRoles": "all",
"collapseItems": []
},
{
"menuSeq": 10,
"isMenu": false,
"menuDesc": "系統參數維護",
"menuUrl": "/system/SysParmDataPage",
"menuFunc": "Edit",
"menuRoles": "all",
"collapseItems": []
}
]
}
]
}
]
}